/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package TimeRecording.tables;

import TimeRecording.enums.MonthStatus;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

/**
 *
 * @author david
 */
@Entity
@Table(name = "monthly_time")
@NamedQueries({
    @NamedQuery(
            name = "MonthlyTime.findAll",
            query = "SELECT m " +
                    "FROM MonthlyTime m"),
    @NamedQuery(
            name = "MonthlyTime.findByEmployeeId",
            query = "SELECT m " +
                    "FROM MonthlyTime m " +
                    "WHERE m.monthlyTimePK.employeeId = :employeeId"),
    @NamedQuery(
            name = "MonthlyTime.findByStartDate",
            query = "SELECT m " +
                    "FROM MonthlyTime m " +
                    "WHERE m.monthlyTimePK.startDate = :startDate"),
    @NamedQuery(
            name = "MonthlyTime.findByEndDate",
            query = "SELECT m " +
                    "FROM MonthlyTime m " +
                    "WHERE m.endDate = :endDate"),
    @NamedQuery(
            name = "MonthlyTime.findByEmployeeAndStartDate",
            query = "SELECT m " +
                    "FROM MonthlyTime m " +
                    "WHERE m.monthlyTimePK.employeeId = :employeeId AND " +
                          "m.monthlyTimePK.startDate = :startDate"),
    @NamedQuery(
            name = "MonthlyTime.findByStatus",
            query = "SELECT m " +
                    "FROM MonthlyTime m " +
                    "WHERE m.status = :status " +
                    "ORDER BY m.monthlyTimePK.startDate DESC"),
    @NamedQuery(
            name = "MonthlyTime.findByEmployeeIdAndStatus",
            query = "SELECT m " +
                    "FROM MonthlyTime m " +
                    "WHERE m.monthlyTimePK.employeeId = :employeeId AND " +
                          "m.status = :status " +
                    "ORDER BY m.monthlyTimePK.startDate DESC"),
    @NamedQuery(
            name = "MonthlyTime.findByClosedDate",
            query = "SELECT m " +
                    "FROM MonthlyTime m " +
                    "WHERE m.closedDate = :closedDate"),
    @NamedQuery(
            name = "MonthlyTime.findByEmployeeAndNewestPreEndDate",
            query = "SELECT m " +
                    "FROM MonthlyTime m " +
                    "WHERE m.monthlyTimePK.employeeId = :employeeId AND " +
                          "m.endDate <= :endDate " +
                    "ORDER BY m.closedDate DESC"),
    @NamedQuery(
            name = "MonthlyTime.findByEmployeeAndNewestPreStartDate",
            query = "SELECT m " +
                    "FROM MonthlyTime m " +
                    "WHERE m.monthlyTimePK.employeeId = :employeeId AND " +
                          "m.monthlyTimePK.startDate <= :startDate " +
                    "ORDER BY m.closedDate DESC")})

public class MonthlyTime implements Serializable {
    
    public final static String BY_EMPLOYEE_AND_START_DATE = "MonthlyTime.findByEmployeeAndStartDate";

    private static final long serialVersionUID = 1L;

    // <editor-fold defaultstate="collapsed" desc="Property Change Support">
    @Transient
    private PropertyChangeSupport changeSupport = new PropertyChangeSupport(this);

    public void addPropertyChangeListener(PropertyChangeListener listener) {
        changeSupport.addPropertyChangeListener(listener);
    }

    public void removePropertyChangeListener(PropertyChangeListener listener) {
        changeSupport.removePropertyChangeListener(listener);
    } // </editor-fold>

    @EmbeddedId
    protected MonthlyTimePK monthlyTimePK;

    @Column(name = "end_date")
    @Temporal(TemporalType.DATE)
    private Date endDate;

    @Column(name = "closed_date")
    @Temporal(TemporalType.DATE)
    private Date closedDate;

    @Column(name = "status")
    private MonthStatus status;

    @Column(name = "sessional_start_date")
    @Temporal(TemporalType.DATE)
    private Date sessionalStartDate;

    @Column(name = "sessional_end_date")
    @Temporal(TemporalType.DATE)
    private Date sessionalEndDate;

    // <editor-fold defaultstate="collapsed" desc="Original Figures">
    @Embedded
    @AttributeOverrides({
        @AttributeOverride(name="clocked", column=@Column(name="clocked")),
        @AttributeOverride(name="entered", column=@Column(name="entered")),
        @AttributeOverride(name="sickness", column=@Column(name="sickness")),
        @AttributeOverride(name="holiday", column=@Column(name="holiday")),
        @AttributeOverride(name="estimated", column=@Column(name="estimated")),

        @AttributeOverride(name="fixedExpected", column=@Column(name="fixed_expected")),
        @AttributeOverride(name="fixedRecorded", column=@Column(name="fixed_recorded")),
        @AttributeOverride(name="fixedSickness", column=@Column(name="fixed_sickness")),
        @AttributeOverride(name="fixedHoliday", column=@Column(name="fixed_holiday")),

        @AttributeOverride(name="semiFlexiExpected", column=@Column(name="semi_flexi_expected")),
        @AttributeOverride(name="semiFlexiRecorded", column=@Column(name="semi_flexi_recorded")),
        @AttributeOverride(name="semiFlexiSickness", column=@Column(name="semi_flexi_sickness")),
        @AttributeOverride(name="semiFlexiHoliday", column=@Column(name="semi_flexi_holiday")),

        @AttributeOverride(name="flexiExpected", column=@Column(name="flexi_expected")),
        @AttributeOverride(name="flexiRecorded", column=@Column(name="flexi_recorded")),
        @AttributeOverride(name="flexiSickness", column=@Column(name="flexi_sickness")),
        @AttributeOverride(name="flexiHoliday", column=@Column(name="flexi_holiday")),

        @AttributeOverride(name="sessionExpected", column=@Column(name="session_expected")),
        @AttributeOverride(name="sessionRecorded", column=@Column(name="session_recorded")),
        @AttributeOverride(name="sessionSickness", column=@Column(name="session_sickness")),
        @AttributeOverride(name="sessionHoliday", column=@Column(name="session_holiday")),

        @AttributeOverride(name="adHocRecorded", column=@Column(name="ad_hoc_recorded")),
        @AttributeOverride(name="adHocSickness", column=@Column(name="ad_hoc_sickness")),
        @AttributeOverride(name="adHocHoliday", column=@Column(name="ad_hoc_holiday"))
    })
    private AllocationOfHours allocation;
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Revised Figures">
    @Embedded
    @AttributeOverrides({
        @AttributeOverride(name="clocked", column=@Column(name="revised_clocked")),
        @AttributeOverride(name="entered", column=@Column(name="revised_entered")),
        @AttributeOverride(name="sickness", column=@Column(name="revised_sickness")),
        @AttributeOverride(name="holiday", column=@Column(name="revised_holiday")),
        @AttributeOverride(name="estimated", column=@Column(name="revised_estimated")),

        @AttributeOverride(name="fixedExpected", column=@Column(name="revised_fixed_expected")),
        @AttributeOverride(name="fixedRecorded", column=@Column(name="revised_fixed_recorded")),
        @AttributeOverride(name="fixedSickness", column=@Column(name="revised_fixed_sickness")),
        @AttributeOverride(name="fixedHoliday", column=@Column(name="revised_fixed_holiday")),

        @AttributeOverride(name="semiFlexiExpected", column=@Column(name="revised_semi_flexi_expected")),
        @AttributeOverride(name="semiFlexiRecorded", column=@Column(name="revised_semi_flexi_recorded")),
        @AttributeOverride(name="semiFlexiSickness", column=@Column(name="revised_semi_flexi_sickness")),
        @AttributeOverride(name="semiFlexiHoliday", column=@Column(name="revised_semi_flexi_holiday")),

        @AttributeOverride(name="flexiExpected", column=@Column(name="revised_flexi_expected")),
        @AttributeOverride(name="flexiRecorded", column=@Column(name="revised_flexi_recorded")),
        @AttributeOverride(name="flexiSickness", column=@Column(name="revised_flexi_sickness")),
        @AttributeOverride(name="flexiHoliday", column=@Column(name="revised_flexi_holiday")),

        @AttributeOverride(name="sessionExpected", column=@Column(name="revised_session_expected")),
        @AttributeOverride(name="sessionRecorded", column=@Column(name="revised_session_recorded")),
        @AttributeOverride(name="sessionSickness", column=@Column(name="revised_session_sickness")),
        @AttributeOverride(name="sessionHoliday", column=@Column(name="revised_session_holiday")),

        @AttributeOverride(name="adHocRecorded", column=@Column(name="revised_ad_hoc_recorded")),
        @AttributeOverride(name="adHocSickness", column=@Column(name="revised_ad_hoc_sickness")),
        @AttributeOverride(name="adHocHoliday", column=@Column(name="revised_ad_hoc_holiday"))
    })
    private AllocationOfHours revisedAllocation;
    // </editor-fold>

    @JoinColumn(name = "employee_id", referencedColumnName = "employee_id", insertable = false, updatable = false)
    @ManyToOne(optional = false)
    private Employee employee;

    public MonthlyTime(int employeeId, Date startDate) {
        this(new MonthlyTimePK(employeeId, startDate));
    }

    public MonthlyTime(MonthlyTimePK monthlyTimePK) {
        this();
        this.monthlyTimePK = monthlyTimePK;
    }

    public MonthlyTime() {
        this.status = MonthStatus.IN_PROGRESS;
    }

    public MonthlyTimePK getMonthlyTimePK() {
        return monthlyTimePK;
    }

    public void setMonthlyTimePK(MonthlyTimePK monthlyTimePK) {
        MonthlyTimePK oldMonthlyTimePK = this.monthlyTimePK;
        this.monthlyTimePK = monthlyTimePK;
        changeSupport.firePropertyChange("monthlyTimePK", oldMonthlyTimePK, monthlyTimePK);
    }

    public Employee getEmployee() {
        return employee;
    }

    public void setEmployee(Employee employee) {
        Employee oldEmployee = this.employee;
        this.employee = employee;
        changeSupport.firePropertyChange("employee", oldEmployee, employee);
    }

    public Date getEndDate() {
        return endDate;
    }

    public void setEndDate(Date endDate) {
        Date oldEndDate = this.endDate;
        this.endDate = endDate;
        changeSupport.firePropertyChange("endDate", oldEndDate, endDate);
    }

    public Date getSessionalStartDate() {
        return sessionalStartDate;
    }

    public void setSessionalStartDate(Date sessionalStartDate) {
        Date oldSessionalStartDate = this.sessionalStartDate;
        this.sessionalStartDate = sessionalStartDate;
        changeSupport.firePropertyChange("sessionalStartDate", oldSessionalStartDate, sessionalStartDate);
    }

    public Date getSessionalEndDate() {
        return sessionalEndDate;
    }

    public void setSessionalEndDate(Date sessionalEndDate) {
        Date oldSessionalEndDate = this.sessionalEndDate;
        this.sessionalEndDate = sessionalEndDate;
        changeSupport.firePropertyChange("sessionalEndDate", oldSessionalEndDate, sessionalEndDate);
    }

    public MonthStatus getStatus() {
        return status;
    }

    public void setStatus(MonthStatus status) {
        MonthStatus oldStatus = this.status;
        this.status = status;
        changeSupport.firePropertyChange("status", oldStatus, status);
    }

    public Date getClosedDate() {
        return closedDate;
    }

    public void setClosedDate(Date closedDate) {
        Date oldClosedDate = this.closedDate;
        this.closedDate = closedDate;
        changeSupport.firePropertyChange("closedDate", oldClosedDate, closedDate);
    }

    public AllocationOfHours getAllocation() {
        return allocation;
    }

    public void setAllocation(AllocationOfHours allocation) {
        AllocationOfHours oldAllocation = this.allocation;
        this.allocation = allocation;
        changeSupport.firePropertyChange("allocation", oldAllocation, allocation);
    }

    public AllocationOfHours getRevisedAllocation() {
        return revisedAllocation;
    }

    public void setRevisedAllocation(AllocationOfHours revisedAllocation) {
        AllocationOfHours oldRevisedAllocation = this.revisedAllocation;
        this.revisedAllocation = revisedAllocation;
        changeSupport.firePropertyChange("revisedAllocation",
                oldRevisedAllocation, revisedAllocation);
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final MonthlyTime other = (MonthlyTime) obj;
        if (this.changeSupport != other.changeSupport && (this.changeSupport == null || !this.changeSupport.equals(other.changeSupport))) {
            return false;
        }
        if (this.monthlyTimePK != other.monthlyTimePK && (this.monthlyTimePK == null || !this.monthlyTimePK.equals(other.monthlyTimePK))) {
            return false;
        }
        if (this.endDate != other.endDate && (this.endDate == null || !this.endDate.equals(other.endDate))) {
            return false;
        }
        if (this.closedDate != other.closedDate && (this.closedDate == null || !this.closedDate.equals(other.closedDate))) {
            return false;
        }
        if (this.allocation != other.allocation && (this.allocation == null || !this.allocation.equals(other.allocation))) {
            return false;
        }
        if (this.revisedAllocation != other.revisedAllocation && (this.revisedAllocation == null || !this.revisedAllocation.equals(other.revisedAllocation))) {
            return false;
        }
        if (this.employee != other.employee && (this.employee == null || !this.employee.equals(other.employee))) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 59 * hash + (this.changeSupport != null ? this.changeSupport.hashCode() : 0);
        hash = 59 * hash + (this.monthlyTimePK != null ? this.monthlyTimePK.hashCode() : 0);
        hash = 59 * hash + (this.endDate != null ? this.endDate.hashCode() : 0);
        hash = 59 * hash + (this.closedDate != null ? this.closedDate.hashCode() : 0);
        hash = 59 * hash + (this.allocation != null ? this.allocation.hashCode() : 0);
        hash = 59 * hash + (this.revisedAllocation != null ? this.revisedAllocation.hashCode() : 0);
        hash = 59 * hash + (this.employee != null ? this.employee.hashCode() : 0);
        return hash;
    }

    public static MonthlyTime get(EntityManager entityManager,
            Date startDate, Employee employee) {

        List<MonthlyTime> list = entityManager
                .createNamedQuery("MonthlyTime.findByEmployeeAndStartDate")
                .setParameter("employeeId", employee.getEmployeeId())
                .setParameter("startDate", startDate)
                .getResultList();

        if (list == null || list.isEmpty()) {
            return null;
        } else {
            return list.get(0);
        }
    }

    public static MonthlyTime getLatest(EntityManager entityManager,
            Employee employee) {

        List<MonthlyTime> list = entityManager
                .createNamedQuery("MonthlyTime.findByEmployeeIdAndStatus")
                .setParameter("employeeId", employee.getEmployeeId())
                .setParameter("status", MonthStatus.IN_PROGRESS)
                .getResultList();

        if (list == null || list.isEmpty()) {
            return null;
        } else {
            return list.get(0);
        }
    }

    public static MonthlyTime getLatestButOne(EntityManager entityManager,
            Employee employee) {

        List<MonthlyTime> list = entityManager
                .createNamedQuery("MonthlyTime.findByEmployeeIdAndStatus")
                .setParameter("employeeId", employee.getEmployeeId())
                .setParameter("status", MonthStatus.PART_PROCESSED)
                .getResultList();

        if (list == null || list.isEmpty()) {
            return null;
        } else {
            return list.get(0);
        }
    }

    public static MonthlyTime getLatestPreEndDate(EntityManager entityManager,
            Date endDate, Employee employee) {

        List<MonthlyTime> list = entityManager
                .createNamedQuery("MonthlyTime.findByEmployeeAndNewestPreEndDate")
                .setParameter("employeeId", employee.getEmployeeId())
                .setParameter("endDate", endDate)
                .getResultList();

        if (list == null || list.isEmpty()) {
            return null;
        } else {
            return list.get(0);
        }
    }

    public static MonthlyTime getLatestPreStartDate(EntityManager entityManager,
            Date startDate, Employee employee) {

        List<MonthlyTime> list = entityManager
                .createNamedQuery("MonthlyTime.findByEmployeeAndNewestPreStartDate")
                .setParameter("employeeId", employee.getEmployeeId())
                .setParameter("startDate", startDate)
                .getResultList();

        if (list == null || list.isEmpty()) {
            return null;
        } else {
            return list.get(0);
        }
    }


    @Override
    public String toString() {
        return "MonthlyTime{" + "changeSupport=" + changeSupport + "monthlyTimePK=" + monthlyTimePK + "endDate=" + endDate + "closedDate=" + closedDate + "allocation=" + allocation + "revisedAllocation=" + revisedAllocation + "employee=" + employee + '}';
    }
}
